package it.blueocean.acanto.entities.platform;

import it.blueocean.acanto.entities.platform.security.Authority;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.Type;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;

/**
 * @author Fabio Mauro
 *
 */
@Entity
@Table(name = "TB_MENU_ITEMS")
@org.hibernate.annotations.Table(appliesTo = "TB_MENU_ITEMS", 
		indexes = {@Index(name = "IDX_PARENT", columnNames = {"PARENT"})})
public class MenuItem implements Serializable, Comparable<MenuItem>
{    
	private static final long serialVersionUID = 3408997041028580563L;

	public static final String ROOT_ITEM_ID = "/";
    
    @Id
	@Column(name = "MENU_ITEM_ID", unique = true, nullable = false)
    private String id = null;

    @Column(name = "PARENT", nullable = true)
	private String parent = null;

    @Column(name = "POSITION", nullable = true)
	private int position = 0;

    @Column(name = "MENU_ITEM_TITLE", nullable = true)
	private String title = null;

    @Column(name = "URL", nullable = true)
	private String url = null;

    @Column(name = "MARKED", nullable = true, columnDefinition = "CHAR(1) DEFAULT 'Y' NOT NULL CHECK (ENABLED IN ('N','Y'))")
    @Type(type="yes_no")
	private boolean marked;

    @Column(name = "ENABLED", nullable = true, columnDefinition = "CHAR(1) DEFAULT 'Y' NOT NULL CHECK (ENABLED IN ('N','Y'))")
    @Type(type="yes_no")
	private boolean enabled;

    @Column(name = "ICON1", nullable = true)
	private String icon1 = null;

    @Column(name = "ICON2", nullable = true)
	private String icon2 = null;

    @ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name="TB_MENU_ITEM_GROUPS", 
			joinColumns={@JoinColumn(name="MENU_ITEM_ID")},
			inverseJoinColumns = {@JoinColumn(name = "GROUP_ID")})
	@Fetch(FetchMode.SUBSELECT)
	private Set<Group> groups = new HashSet<Group>();
    
    @Transient
    private List <MenuItem> children = new ArrayList<MenuItem>();
    
    @Transient
    private boolean selected = false;
    
    @Transient
    private MenuItem parentRef = null;
    
    @Column(name = "ITEM_TYPE", nullable = false)
    private String itemType = null;
    
    @Column(name = "ITEM_CATEGORY", nullable = false)
    private String itemCategory = null;
          
    
    public MenuItem()
    {
    }
    
    public MenuItem getChild(int index)
    {
        if( index < children.size() && index >= 0)
            return children.get(index);
        return null;
    }
    
    public MenuItem getSelectedChild()
    {
        for(MenuItem mi: children)
            if (mi.isSelected())
                return mi;
        return null;
    }
    
    public boolean hasSelectedChild()
    {
        for(MenuItem mi: children)
            if (mi.isSelected())
                return true;
        return false;
    }
    
    public boolean isItemVisible(Collection<GrantedAuthority> userGrantedAuthorities)
    {     
		if(userGrantedAuthorities == null || userGrantedAuthorities.size() == 0)
			return false;

		Set<Authority> authorities = new HashSet<Authority>();
		
		for (Group group : groups)
		{
			authorities.addAll(group.getRoles());
		}
		
		Set<GrantedAuthority> menuItemGrantedAuthorities = new HashSet<GrantedAuthority>();
		
		for (Authority authority : authorities)
		{
			menuItemGrantedAuthorities.add(new GrantedAuthorityImpl(authority.getAuthority()));
		}
		
		if(userGrantedAuthorities.containsAll(menuItemGrantedAuthorities))
		{
			return true;
		}

		return false;
	}
    
    public MenuItem clone()
    {
        MenuItem clone = new MenuItem();
        clone.setId(getId());            
        clone.setParent(getParent());        
        clone.setPosition(getPosition());
        clone.setTitle(getTitle());
        clone.setUrl(getUrl());
        clone.setMarked(isMarked());
        clone.setEnabled(isEnabled());
        clone.setIcon1(getIcon1());
        clone.setIcon2(getIcon2());   
        
        for (Group group : groups)
            clone.getGroups().add((Group)group); 
        
        return clone;
    }
    
    public boolean equals(Object anObject)
    {
        return id.equals(anObject);
    }
        
    public String toString()
    {
        return new StringBuffer()
                        .append("id : " + id).append("\n") 
                        .append("parent : " + parent).append("\n") 
                        .append("position : " + position).append("\n") 
                        .append("title : " + title).append("\n") 
                        .append("url : " + url).append("\n")
                        .append("marked : " + marked).append("\n") 
                        .append("enabled : " + enabled).append("\n") 
                        .append("icon1 : " + icon1).append("\n") 
                        .append("icon2 : " + icon2).append("\n") 
                        .append("selected : " + selected).append("\n") 
                        .append("parentRef : " + parentRef).append("\n") 
                        .append("itemType : " + itemType).append("\n") 
                        .append("itemCategory : " + itemCategory).append("\n") 
                        .toString();
    }
    
    public int compareTo(MenuItem arg0)
    {
        int result = this.getPosition() - ((MenuItem)arg0).getPosition();
        
        if(result < 0)
            return -1;
        else if(result == 0)
            return 0;
        else
            return 1;
    }       
    
    public String getPermissionsToString()
    {
        String associatedGroups = "";
        
        for(Group group: groups )
            associatedGroups += "'" + group.getId() + "',";

        // strips the last comma
        if(associatedGroups.trim().length() > 0)
            return associatedGroups.substring(0, associatedGroups.length() - 1 ) + "";
        else
            return "";
    }
    
    
   
    /*
     * getter / setter methods
     */
	public boolean isEnabled()
	{
		return enabled;
	}

	public void setEnabled(boolean enabled)
	{
		this.enabled = enabled;
	}

	public String getIcon1()
	{
		return icon1;
	}

	public void setIcon1(String icon1)
	{
		this.icon1 = icon1;
	}

	public String getIcon2()
	{
		return icon2;
	}

	public void setIcon2(String icon2)
	{
		this.icon2 = icon2;
	}

	public String getId()
	{
		return id;
	}

	public void setId(String id)
	{
		this.id = id;
	}

	public boolean isMarked()
	{
		return marked;
	}

	public void setMarked(boolean marked)
	{
		this.marked = marked;
	}

	public String getParent()
	{
		return parent;
	}

	public void setParent(String parent)
	{
		this.parent = parent;
	}

	public Set<Group> getGroups()
	{
		return groups;
	}

	public void setGroups(Set<Group> groups)
	{
		this.groups = groups;
	}

	public int getPosition()
	{
		return position;
	}

	public void setPosition(int position)
	{
		this.position = position;
	}

	public String getTitle()
	{
		return title;
	}

	public void setTitle(String title)
	{
		this.title = title;
	}

	public String getUrl()
	{
		return url;
	}

	public void setUrl(String url)
	{
		this.url = url;
	}

	public List<MenuItem> getChildren()
	{
		return children;
	}

	public void setChildren(List<MenuItem> children)
	{
		this.children = children;
	}

	public boolean isSelected()
	{
		return selected;
	}

	public void setSelected(boolean selected)
	{
		this.selected = selected;
	}

	public String getItemCategory()
	{
		return itemCategory;
	}

	public void setItemCategory(String itemCategory)
	{
		this.itemCategory = itemCategory;
	}

	public String getItemType()
	{
		return itemType;
	}

	public void setItemType(String itemType)
	{
		this.itemType = itemType;
	}

	public MenuItem getParentRef()
	{
		return parentRef;
	}

	public void setParentRef(MenuItem parentRef)
	{
		this.parentRef = parentRef;
	}
    
}
